package org.convallaria.infrastruct.ce.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.stream.Collectors;

/**
 * 缓存键生成器
 * 提供统一的缓存键生成策略
 * 
 * @author gjh
 * @since 2024-09-24
 */
@Slf4j
@Component("cacheKeyGenerator")
public class CacheKeyGenerator implements KeyGenerator {

    private static final String DEFAULT_SEPARATOR = ":";
    private static final String NULL_VALUE = "null";

    @Override
    public Object generate(Object target, Method method, Object... params) {
        return generateKey(method.getName(), params);
    }

    /**
     * 生成缓存键
     * 
     * @param methodName 方法名
     * @param params 参数
     * @return 缓存键
     */
    public String generateKey(String methodName, Object... params) {
        if (params.length == 0) {
            return methodName;
        }
        
        String key = methodName + DEFAULT_SEPARATOR + 
                Arrays.stream(params)
                        .map(this::formatParam)
                        .collect(Collectors.joining(DEFAULT_SEPARATOR));
        
        // 限制键长度，避免过长的键
        if (key.length() > 250) {
            key = methodName + DEFAULT_SEPARATOR + String.valueOf(Arrays.hashCode(params));
        }
        
        return key;
    }

    /**
     * 生成带前缀的缓存键
     * 
     * @param prefix 前缀
     * @param methodName 方法名
     * @param params 参数
     * @return 缓存键
     */
    public String generateKey(String prefix, String methodName, Object... params) {
        String key = generateKey(methodName, params);
        return StringUtils.isNotBlank(prefix) ? prefix + DEFAULT_SEPARATOR + key : key;
    }

    /**
     * 生成基于类的缓存键
     * 
     * @param clazz 类
     * @param methodName 方法名
     * @param params 参数
     * @return 缓存键
     */
    public String generateKey(Class<?> clazz, String methodName, Object... params) {
        String className = clazz.getSimpleName();
        return generateKey(className, methodName, params);
    }

    /**
     * 格式化参数
     * 
     * @param param 参数
     * @return 格式化后的字符串
     */
    private String formatParam(Object param) {
        if (param == null) {
            return NULL_VALUE;
        }
        
        if (param instanceof String) {
            return (String) param;
        }
        
        if (param instanceof Number || param instanceof Boolean) {
            return param.toString();
        }
        
        if (param.getClass().isArray()) {
            return Arrays.toString((Object[]) param);
        }
        
        // 对于复杂对象，使用hashCode
        return String.valueOf(param.hashCode());
    }

    /**
     * 生成简单的缓存键（仅使用参数）
     * 
     * @param params 参数
     * @return 缓存键
     */
    public String generateSimpleKey(Object... params) {
        if (params.length == 0) {
            return "empty";
        }
        
        if (params.length == 1) {
            return formatParam(params[0]);
        }
        
        return Arrays.stream(params)
                .map(this::formatParam)
                .collect(Collectors.joining(DEFAULT_SEPARATOR));
    }
}
